#include "led.h"
#include "key.h"
#include "delay.h"
#include "usart.h"
#include <string.h>
#include <stdio.h>

uint8_t buffer[100]            = {0};
uint8_t size                   = 0;
uint8_t receive_one_frame_flag = 0;

// 自定义函数：查询各个时钟频率（系统时钟sysclock、AHB、APB2、APB1）
void get_clock_freq(uint32_t *sys_clock, uint32_t *AHB_clock, uint32_t *APB2_clock, uint32_t *APB1_clock)
{
    // 1. 获取时钟源
    uint32_t clock_src = RCC->CFGR & RCC_CFGR_SWS;

    // 2. 根据时钟源获取系统时钟频率
    if (clock_src == RCC_CFGR_SWS_HSE)
    {
        *sys_clock = HSE_VALUE;
    }
    else if (clock_src == RCC_CFGR_SWS_HSI)
    {
        *sys_clock = HSI_VALUE;
    }
    else if (clock_src == RCC_CFGR_SWS_PLL)
    {
        // 取倍频系数相乘
        uint32_t mul = ((RCC->CFGR & RCC_CFGR_PLLMULL) >> 18) + 2;
        *sys_clock = HSE_VALUE * mul;
    }

    // 3. 根据分频系数，确定各个时钟频率
    // 3.1 AHB
    // 3.1.1 获取分频系数
    uint32_t hpre = (RCC->CFGR & RCC_CFGR_HPRE) >> 4;
    // 3.1.2 根据最高位，判断是否有分频
    if (hpre & 0x8)
    {
        // 有分频，取最后三位
        uint32_t n = hpre & 0x7;
        // 跟4做比较，选择右移n+1位或者n+2位
        if (n < 4)
        {
            *AHB_clock = *sys_clock >> (n+1);
        }
        else
        {
            *AHB_clock = *sys_clock >> (n+2);
        }
    }
    else
    {
        // 没有分频
        *AHB_clock = *sys_clock;
    }

    // 3.2 APB1
    // 3.2.1 获取分频系数
    uint32_t ppre1 = (RCC->CFGR & RCC_CFGR_PPRE1) >> 8;
    // 3.2.2 根据最高位，判断是否有分频
    if (ppre1 & 0x4)
    {
        *APB1_clock = *AHB_clock >> ((ppre1 & 0x3) + 1);
    }
    else
    {
        // 没有分频
        *APB1_clock = *AHB_clock;
    }

    // 3.3 APB2
    // 3.3.1 获取分频系数
    uint32_t ppre2 = (RCC->CFGR & RCC_CFGR_PPRE2) >> 11;
    // 3.3.2 根据最高位，判断是否有分频
    if (ppre2 & 0x4)
    {
        *APB2_clock = *AHB_clock >> ((ppre2 & 0x3) + 1);
    }
    else
    {
        // 没有分频
        *APB2_clock = *AHB_clock;
    }
}

// 定义进入睡眠模式的函数
void enter_stop_mode(void)
{
    // 1. 设置深睡眠模式
    SCB->SCR |= SCB_SCR_SLEEPDEEP;

    // 2. 开启PWR模块时钟
    RCC->APB1ENR |= RCC_APB1ENR_PWREN;

    // 3. 配置PDDS = 0，表示停机模式
    PWR->CR &= ~PWR_CR_PDDS;

    // 4. 设置电压调节器的工作模式：低功耗模式
    PWR->CR |= PWR_CR_LPDS;

    // 5. 使用WFI指令，进入停机模式
    __WFI();
}

// 定义进入待机模式的函数
void enter_standby_mode(void)
{
    // 1. 设置深睡眠模式
    SCB->SCR |= SCB_SCR_SLEEPDEEP;

    // 3. 配置PDDS = 1，表示待机模式
    PWR->CR |= PWR_CR_PDDS;

    // 4. 使能 PA0 的唤醒功能
    PWR->CSR |= PWR_CSR_EWUP;

    // 5. 使用WFI指令，进入待机模式
    __WFI();
}

int main(void)
{
    // 初始化
    USART_Init();
    Key_Init();
    LED_Init();

    LED_On(LED1);

    // 发送单个字符
    USART_SendChar('a');
    USART_SendChar('t');
    USART_SendChar('\n');

    // 开启PWR模块时钟
    RCC->APB1ENR |= RCC_APB1ENR_PWREN;

    // 判断是否有标志位，如果有就直接清除
    if (PWR->CSR & PWR_CSR_SBF)
    {
        printf("wake up from standby mode!\n");
        PWR->CR |= PWR_CR_CSBF;
    }
    if (PWR->CSR & PWR_CSR_WUF)
    {
        printf("wake up event flag is set!\n");
        PWR->CR |= PWR_CR_CWUF;
    }

    // 发送字符串
    uint8_t *str = "program start!\n";
    USART_SendString(str, strlen((char *)str));

    while(1)
    {
        str = "would enter standby mode!\n";
        USART_SendString(str, strlen((char *)str));
        Delay_s(2);
        str = "would enter standby mode2!\n";
        USART_SendString(str, strlen((char *)str));
        Delay_ms(10);

        // 进入停止模式
        enter_standby_mode();

        str = "exit from standby mode!\n";
        USART_SendString(str, strlen((char *)str));

        str = "exit from standby mode2!\n";
        USART_SendString(str, strlen((char *)str));

        str = "exit from standby mode3!\n";
        USART_SendString(str, strlen((char *)str));
    }
}

